package com.project.web.admin.utils.shiro;

import com.project.common.web.utils.config.prop.PropAttributes;
import com.project.common.web.utils.config.prop.PropConfig;
import com.project.model.core.Admin;
import com.project.model.core.Menu;
import com.project.model.core.Role;
import com.project.web.admin.service.core.AdminService;
import com.project.web.admin.service.core.MenuService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 认证
 */
public class AuthenticationRealm extends AuthorizingRealm {

    @Resource(name = "adminServiceImpl")
    private AdminService adminService;

    @Resource(name = "menuServiceImpl")
    private MenuService menuService;

    @Resource(name = "redisCaptchaService")
    private com.octo.captcha.service.CaptchaService imageCaptchaService;

    /**
     * 获取认证信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken token) {
        com.project.web.admin.utils.shiro.AuthenticationToken authToken = (com.project.web.admin.utils.shiro.AuthenticationToken) token;
        //获取登录名、密码、验证码ID、验证码
        String username = authToken.getUsername();
        String password = new String(authToken.getPassword());
//        String captchaId = authToken.getCaptchaId();
//        String captcha = authToken.getCaptcha();

        //暂时去除验证码
//        if (!imageCaptchaService.validateResponseForID(captchaId, captcha.toUpperCase())) {
//            throw new UnsupportedTokenException();
//        }


        if (username != null && password != null) {
            Admin adminTemp = new Admin();
            adminTemp.setMobile(username);
            List<Admin> adminList = adminService.selectListForLogin(adminTemp);

            if (CollectionUtils.isEmpty(adminList) || adminList.size() > 1) {
                throw new UnknownAccountException();
            }

            Admin admin = adminList.get(0);
            if (admin.getStatus() != 0) {
                throw new DisabledAccountException();
            }

            //用户锁定
            if (admin.getIsLocked()) {

                //账号锁定分钟数
                String accountLockMinutes = PropConfig.getProperty(PropAttributes.SYSTEM_ACCOUNTLOCKMINUTES);
                if (StringUtils.isBlank(accountLockMinutes)) {
                    throw new LockedAccountException();
                }

                int loginFailTime = Integer.parseInt(accountLockMinutes);

                if (loginFailTime == 0) {
                    throw new LockedAccountException();
                }
                Date lockedDate = admin.getLockedDate();
                Date unlockedDate = DateUtils.addMinutes(lockedDate, loginFailTime);

                //判断锁定时间是否已过
                if (new Date().after(unlockedDate)) {
                    admin.setLoginFailCount(0);
                    admin.setIsLocked(false);
                    admin.setLockedDate(null);
                    if (admin.getStatus() == 1) {
                        admin.setStatus(0);
                    }
                    adminService.update(admin);
                } else {
                    throw new LockedAccountException();
                }
            }

            //密码不正确
            if (!DigestUtils.md5Hex(password).equals(admin.getPassword())) {
                int loginFailCount = admin.getLoginFailCount() + 1;
                int accountLockCount = Integer.parseInt(PropConfig.getProperty(PropAttributes.SYSTEM_ACCOUNTLOCKCOUNT));
                if (loginFailCount >= accountLockCount) {
                    admin.setIsLocked(true);
                    admin.setLockedDate(new Date());
                }
                admin.setLoginFailCount(loginFailCount);
                adminService.update(admin);
                throw new IncorrectCredentialsException();
            }
            admin.setLoginFailCount(0);
            adminService.update(admin);
            return new SimpleAuthenticationInfo(new Principal(admin.getId(), username), password, getName());
        }
        throw new UnknownAccountException();
    }

    /**
     * 获取授权信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        Principal principal = (Principal) principals.fromRealm(getName()).iterator().next();

        if (principal != null) {
            SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();

            //获取admin对象
            Admin adminTemp = new Admin();
            adminTemp.setId(principal.getId());
            List<Admin> roleList = adminService.getAdminCascadeRole(adminTemp);
            Admin admin = roleList.get(0);

            //获取用户的角色信息
            Set<String> roleSet = new HashSet<String>();
            for (Role role : admin.getRoles()) {
                if (role.getStatus().equals(0)) {
                    roleSet.add(role.getRoleCode());
                }
            }

            //根据角色ids获取权限信息
            List<Menu> menuList = menuService.findOrdinaryMenu(principal.getId());
            Set<String> menuSet = new HashSet<String>();
            for (Menu menu : menuList) {
                if (StringUtils.isNotBlank(menu.getUrl())) {
                    menuSet.add(menu.getUrl());
                }
            }

            //将角色和资源放入授权对象中
            authInfo.addRoles(roleSet);
            authInfo.addStringPermissions(menuSet);

            return authInfo;
        }

        return null;
    }

}
